package br.com.nemesis.dao;

import br.com.nemesis.excecao.PersistenciaExcecao;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class DAOGenerico<T, PK extends Serializable> implements DAO<T, PK>  {

    protected Class<T> tipo;
    private EntityManager entityManager;
    private EntityManagerFactory emf;

    public DAOGenerico() {
        this.tipo = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        emf = Persistence.createEntityManagerFactory("nemesisPU");
        entityManager = emf.createEntityManager();
    }

    public List<T> listar() throws PersistenciaExcecao {
        List<T> resultados = null;
        try {
            resultados = entityManager.createQuery("select entidade from " + tipo.getSimpleName() + " entidade").getResultList();
        } catch (Exception e) {
            entityManager.close();
            emf.close();
            throw new PersistenciaExcecao(e.getMessage());
        }finally{
            entityManager.close();
            emf.close();
        }        
        return resultados;
    }

    public T buscar(PK pk) throws PersistenciaExcecao {
        return entityManager.find(tipo, pk);
    }

    public T salvar(T entidade) throws PersistenciaExcecao {
        try {
            entityManager.getTransaction().begin();
            entityManager.persist(entidade);            
        } catch (Exception e) {
            entityManager.getTransaction().rollback();
            entityManager.close();
            emf.close();
        } finally{
            entityManager.getTransaction().commit();
            entityManager.close();
            emf.close();
        }        
	return entidade;
    }

    public void alterar(T entidade) throws PersistenciaExcecao {
        try {
            entityManager.getTransaction().begin();
            entityManager.merge(entidade);
        } catch (Exception e) {
            entityManager.getTransaction().rollback();
            entityManager.close();
            emf.close();
        } finally{
            entityManager.getTransaction().commit();
            entityManager.close();
            emf.close();
        }
    }

    public void remover(T entidade) throws PersistenciaExcecao {
        Object toRemove = entityManager.merge(entidade);
        try {
            entityManager.getTransaction().begin();
            entityManager.remove(toRemove);
        } catch (Exception e) {
            entityManager.getTransaction().rollback();
            entityManager.close();
            emf.close();
        } finally{
            entityManager.getTransaction().commit();
            entityManager.close();
            emf.close();
        }	
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

}